package pdfsetter.core.schema;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import pdfsetter.core.pages.PageInfo;
import pdfsetter.core.pages.PageRectangle;
import pdfsetter.core.util.RandomAccessIterable;

/**
 * This class is implementation of {@link DocumentSchema} in which every page has the same arrangement. It is product of combining single page schema with set
 * of page selections.
 * 
 * @author Andrzej Dorobisz
 */
public class SimpleDocumentSchema implements DocumentSchema {
    private final PageInfo pageInfo;
    private final PageRectangle pageLocations[];
    private final RandomAccessIterable<PageSelection> pageSelections;
    private final int expectedNumberOfFiles;

    public SimpleDocumentSchema(SinglePageSchema pageSchema, FillingSchema fillingSchema) {
        this.pageInfo = pageSchema.getPageInfo();
        this.pageSelections = fillingSchema.getPageSelections();
        List<PageRectangle> schemaPageLocations = pageSchema.getPageLocations();
        this.pageLocations = new PageRectangle[schemaPageLocations.size()];
        int index = 0;
        for (PageRectangle rectangle : schemaPageLocations) {
            this.pageLocations[index] = rectangle;
            index++;
        }
        expectedNumberOfFiles = fillingSchema.getExpectedNumberOfFiles();
    }

    @Override
    public Iterable<PageBuildSchema> getPageBuildSchemas() {
        return new Iterable<PageBuildSchema>() {
            @Override
            public Iterator<PageBuildSchema> iterator() {
                return new SimpleDocumentSchemaIterator();
            }
        };
    }

    @Override
    public int getExpectedNumberOfFiles() {
        return expectedNumberOfFiles;
    }

    private class SimpleDocumentSchemaIterator implements Iterator<PageBuildSchema> {
        private int nextPage;

        SimpleDocumentSchemaIterator() {
            nextPage = 0;
        }

        @Override
        public boolean hasNext() {
            return nextPage * pageLocations.length < pageSelections.size();
        }

        @Override
        public PageBuildSchema next() {
            if (!hasNext())
                throw new NoSuchElementException();
            else {
                ArrayList<PageInsertSchema> pageInsertSchemas = new ArrayList<PageInsertSchema>(pageLocations.length);
                for (int i = 0, index = nextPage * pageLocations.length; i < pageLocations.length && index < pageSelections.size(); i++, index++) {
                    PageSelection ps = pageSelections.get(index);
                    if (ps.getFileNumber() < 0)
                        continue;
                    else
                        pageInsertSchemas.add(new PageInsertSchema(ps, pageLocations[i]));
                }
                nextPage++;
                return new PageBuildSchema(pageInsertSchemas, pageInfo);
            }
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
